#pragma once

#include <iostream>
#include <vector>
#include "Sem.hpp"
#include "Mutex.hpp"

static const int gcap = 5;
using namespace SemModule;
using namespace MutexModule;

template <typename T>
class RingQueue
{
public:
    RingQueue(int cap = gcap)
        : _rq(cap),
          _cap(cap),
          _blank_sem(cap),
          _p_step(0),
          _data_sem(0),
          _c_step(0)
    {
    }
    void Equeue(const T &in)
    {
        // 生产者
        //_pmutex.Lock();
        // 1.申请信号量
        _blank_sem.P();

        {
            LockGuard lockguard(_pmutex);
            // 这里加锁解锁也可以,电影院先买票再排队 > 先排队再买票
            //_pmutex.Lock()//更高效
            //  2.生产数据
            _rq[_p_step] = in;
            // 3.更新下标
            (++_p_step) %= _cap;
            // 4.通知消费者
            //_pmutex.Unlock()//这里加锁解锁也可以
        }

        _data_sem.V();
        //_pmutex.Unlock();
    }
    void Pop(T *out)
    {
        // 消费者
        //_cmutex.Lock();
        // 1.申请信号量
        _data_sem.P();

        {
            LockGuard lockguard(_cmutex);
            // 2.消费数据
            *out = _rq[_c_step];
            // 3.更新下标
            (++_c_step) %= _cap;
        }

        // 4.通知生产者
        _blank_sem.V();
        //_cmutex.Unlock();
    }
    ~RingQueue()
    {
    }

private:
    std::vector<T> _rq;
    int _cap;

    Sem _blank_sem; // 生产者关注空格
    int _p_step;

    Sem _data_sem; // 消费者关注数据
    int _c_step;

    // 维护多生产多消费,两把锁
    Mutex _pmutex;
    Mutex _cmutex;
};